﻿using Crux.Core.SQL.Formatter.Core;
using Crux.Core.SQL.Formatter.Language;

namespace Crux.Core.SQL.Formatter;
/// <summary>
/// 
/// </summary>
public class SqlFormatter
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="query"></param>
    /// <param name="cfg"></param>
    /// <returns></returns>
    public static string Format(string query, FormatConfig cfg)
    {
        return Standard().Format(query, cfg);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="query"></param>
    /// <param name="indent"></param>
    /// <param name="parameters"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static string Format<T>(string query, string indent, List<T> parameters)
    {
        return Standard().Format(query, indent, parameters);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="query"></param>
    /// <param name="parameters"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static string Format<T>(string query, List<T> parameters)
    {
        return Standard().Format(query, parameters);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="query"></param>
    /// <param name="indent"></param>
    /// <param name="parameters"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static string Format<T>(string query, string indent, Dictionary<string, T> parameters)
    {
        return Standard().Format(query, indent, parameters);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="query"></param>
    /// <param name="parameters"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static string Format<T>(string query, Dictionary<string, T> parameters)
    {
        return Standard().Format(query, parameters);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="query"></param>
    /// <param name="indent"></param>
    /// <returns></returns>
    public static string Format(string query, string indent)
    {
        return Standard().Format(query, indent);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="query"></param>
    /// <returns></returns>
    public static string Format(string query)
    {
        return Standard().Format(query);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sqlOperator"></param>
    /// <returns></returns>
    public static Formatter Extend(Func<DialectConfig, DialectConfig> sqlOperator)
    {
        return Standard().Extend(sqlOperator);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public static Formatter Standard()
    {
        return Of(Dialect.StandardSql);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public static Formatter Of(string name)
    {
        var dialect = Dialect.NameOf(name);
        return dialect is null ? throw new Exception("Unsupported SQL dialect: " + name) :
            new Formatter(dialect);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="dialect"></param>
    /// <returns></returns>
    public static Formatter Of(Dialect dialect)
    {
        return new Formatter(dialect);
    }
    /// <summary>
    /// 
    /// </summary>
    public class Formatter
    {
        private readonly Func<FormatConfig, AbstractFormatter> underlying;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="underlying"></param>
        public Formatter(Func<FormatConfig, AbstractFormatter> underlying)
        {
            this.underlying = underlying;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dialect"></param>
        /// <returns></returns>
        public Formatter(Dialect dialect) : this(dialect.func) { }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="cfg"></param>
        /// <returns></returns>
        public string Format(string query, FormatConfig cfg)
        {
            return underlying.Invoke(cfg).Format(query);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="indent"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public string Format<T>(string query, string indent, List<T> parameters)
        {
            return Format(query, FormatConfig.Builder().Indent(indent).Params(parameters).Build());
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="parameters"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public string Format<T>(string query, List<T> parameters)
        {
            return Format(query, FormatConfig.Builder().Params(parameters).Build());
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="indent"></param>
        /// <param name="parameters"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public string Format<T>(string query, string indent, Dictionary<string, T> parameters)
        {
            return Format(query, FormatConfig.Builder().Indent(indent).Params(parameters).Build());
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="parameters"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public string Format<T>(string query, Dictionary<string, T> parameters)
        {
            return Format(query, FormatConfig.Builder().Params(parameters).Build());
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="indent"></param>
        /// <returns></returns>
        public string Format(string query, string indent)
        {
            return Format(query, FormatConfig.Builder().Indent(indent).Build());
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public string Format(string query)
        {
            return Format(query, FormatConfig.Builder().Build());
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sqlOperator"></param>
        /// <returns></returns>
        public Formatter Extend(Func<DialectConfig, DialectConfig> sqlOperator)
        {
            AbstractFormatter Func(FormatConfig config)
            {
                var abstractFormatter = new AbstractFormatter(config)
                {
                    doDialectConfigFunc = () => sqlOperator.Invoke(underlying.Invoke(config).DoDialectConfig())
                };
                return abstractFormatter;
            }

            return new Formatter(Func);
        }
    }
}